# -*- encoding: utf-8 -*-

"""
@File:      tc_lmdb_lmdb_func_003.py
@Time:      2024/03/27 14:33:20
@Author:    chenchunhu
@Version:   1.0
@Contact:   wb-cch358909@alibaba-inc.com
@License:   Mulan PSL v2
@Modify:    chenchunhu
"""

from common.basetest import LocalTest

class Test(LocalTest):
    """
    See tc_lmdb_lmdb_func_003.yaml for details

    :avocado: tags=P2,noarch,local,fix
    """

    PARAM_DIC = {"pkg_name": "lmdb lmdb-devel gcc"}
    def setUp(self):
        super().setUp(self.PARAM_DIC)
        cmdline = '''cat >lmdb_test2.c<<"EOF"
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include "lmdb.h"

#define NUM_THREADS 10
#define TEST_DB_SIZE (10485760)
#define ENV_PATH "./lmdb_test2_db"

// 用于线程传递参数的结构
struct thread_info {
    MDB_env *env;
    int thread_id;
};

// 线程函数的原型，每个线程都执行这个函数
void *thread_func(void *arg) {
    struct thread_info *info = (struct thread_info *)arg;
    MDB_txn *txn;
    MDB_dbi dbi;
    MDB_val key, data;
    char sval[32];
    int rc;

    // 开始事务
    rc = mdb_txn_begin(info->env, NULL, 0, &txn);
    if(rc != MDB_SUCCESS) {
        fprintf(stderr, "Transaction begin failed: %s\\n", mdb_strerror(rc));
        pthread_exit((void*)EXIT_FAILURE);
    }

    // 打开数据库
    rc = mdb_dbi_open(txn, NULL, 0, &dbi);
    if(rc != MDB_SUCCESS) {
        mdb_txn_abort(txn);
        fprintf(stderr, "DBI open failed: %s\\n", mdb_strerror(rc));
        pthread_exit((void*)EXIT_FAILURE);
    }

    // 准备数据
    key.mv_size = sizeof(int);
    key.mv_data = &info->thread_id;
    data.mv_size = sprintf(sval, "thread_id_%d", info->thread_id) + 1;
    data.mv_data = sval;

    // 写入数据
    rc = mdb_put(txn, dbi, &key, &data, 0);
    if(rc != MDB_SUCCESS) {
        mdb_txn_abort(txn);
        fprintf(stderr, "Data put failed: %s\\n", mdb_strerror(rc));
        pthread_exit((void*)EXIT_FAILURE);
    }

    // 提交事务
    rc = mdb_txn_commit(txn);
    if(rc != MDB_SUCCESS) {
        fprintf(stderr, "Transaction commit failed: %s\\n", mdb_strerror(rc));
        pthread_exit((void*)EXIT_FAILURE);
    }

    // 清理
    mdb_dbi_close(info->env, dbi);

    printf("Thread %d successfully wrote to the database\\n", info->thread_id);
    pthread_exit((void*)EXIT_SUCCESS);
}

int main() {
    MDB_env *env;
    pthread_t threads[NUM_THREADS];
    struct thread_info thread_data[NUM_THREADS];
    int rc, i;

    // 创建一个LMDB环境句柄
    mdb_env_create(&env);
    mdb_env_set_mapsize(env, TEST_DB_SIZE);
    mdb_env_open(env, ENV_PATH, 0, 0664);

    // 创建并启动线程
    for (i = 0; i < NUM_THREADS; i++) {
        thread_data[i].env = env;
        thread_data[i].thread_id = i;
        if (pthread_create(&threads[i], NULL, thread_func, (void*)&thread_data[i]) != 0) {
            perror("pthread_create");
            mdb_env_close(env);
            exit(EXIT_FAILURE);
        }
    }

    // 等待线程结束
    for (i = 0; i < NUM_THREADS; i++) {
        void *status;
        if (pthread_join(threads[i], &status) != 0) {
            perror("pthread_join");
        } else {
            printf("Thread %d finished with status %ld\\n", i, (long)status);
        }
    }

    // 关闭环境
    mdb_env_close(env);

    return EXIT_SUCCESS;
}
EOF'''
        self.cmd(cmdline)
        self.cmd("mkdir -p lmdb_test2_db")


    def test(self):
        self.cmd("gcc lmdb_test2.c -o lmdb_test2 -llmdb -lpthread")
        code, lmdb_result = self.cmd("./lmdb_test2")
        self.assertIn("Thread 9 finished with status 0", lmdb_result)

    def tearDown(self):
        super().tearDown(self.PARAM_DIC)
        self.cmd("rm -rf lmdb_test2.c lmdb_test2 lmdb_test2_db")
